package com.eken.bgm.model.project;

import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.dom4j.Node;
import org.dom4j.Element;

import com.eken.bgm.model.message.MessageBuffer;
import com.eken.bgm.model.message.MessageBuffer.MessageType;

/**
 * Handles the project xml file and handles the different components
 * and entities associated with the project.
 * 
 * @author Gabriel Ekblad
 *
 */
public final class ProjectHandler {

	private final static String PROJECT_FILE_NAME = ".project";

	private MessageBuffer msgBuffer;

	private String projectName;

	private String projectXMLFile;

	// Component name, Script location
	private List<Component> components;

	// Entity name, Components attached to entity
	private List<Entity> entities;

	/**
	 * Constructs the project handler. Will parse the project xml file.
	 * @param projectXMLFile	The project file to read from.
	 */
	public ProjectHandler(String projectXMLFile) {
		this.projectXMLFile = projectXMLFile;
		this.components = new ArrayList<Component>();
		this.entities = new ArrayList<Entity>();
		this.msgBuffer = MessageBuffer.getInstance();
		this.parseXML(projectXMLFile);
	}

	private boolean parseXML(String projectXMLFile) {
		File projectFile = new File(projectXMLFile);

		if(projectFile.exists() && projectFile.isFile() && projectFile.getName().equals(PROJECT_FILE_NAME)) {
			return this.parseXML(projectFile);
		} else if(projectFile.isDirectory()) {
			for(File f : projectFile.listFiles()) {
				if(f.getName().equals(PROJECT_FILE_NAME)) {
					return this.parseXML(f);
				}
			}
		}

		return false;
	}

	private boolean parseXML(File f) {
		try {
			SAXReader reader = new SAXReader();
			Document d = reader.read(f);

			Element root = d.getRootElement();
			this.projectName = root.attribute("name").getValue();

			Iterator<?> i = root.elementIterator();

			while(i.hasNext()) {
				Element e = (Element) i.next();

				if(e.getName().equals("components")) {
					this.initComponents(e);
				} else if(e.getName().equals("entities")) {
					this.initEntities(e);
				}
			}

		} catch (DocumentException e) {
			this.msgBuffer.append(MessageType.ERROR, e.getMessage());
			return false;
		}

		return true;
	}

	private boolean initEntities(Element e) {
		Iterator<?> iEntities = e.elementIterator();
		
		while(iEntities.hasNext()) {
			Element eEntity = (Element) iEntities.next();
			
			String entityName = eEntity.attributeValue("name");
			List<?> eComponents = eEntity.elements("component");
			
			// the list which will hold the components for the entity.
			List<Component> components = new ArrayList<Component>();
			
			for(int i = 0; i < eComponents.size(); i++) {
				Element eComp = (Element) eComponents.get(i);
				
				String componentName = eComp.getStringValue();
				
				// check if the component actually exist in the project.
				Component c = this.getComponent(componentName);
				
				if(c != null) {
					components.add(c);
				} else {
					this.msgBuffer.append(MessageType.ERROR, "An entity was mapped to a component which doesn't exist!");
					return false;
				}
			}
			
			this.entities.add(new Entity(entityName, components));
		}
		
		return true;
	}

	private boolean initComponents(Element e) {
		List<?> components = e.elements();

		Iterator<?> iComps = components.iterator();

		while(iComps.hasNext()) {
			Element eComp = (Element) iComps.next();
			String componentName = eComp.attributeValue("name");
			String scriptLocation = eComp.element("script").getStringValue();
			this.components.add(new Component(componentName, scriptLocation));
		}

		return true;
	}
	
	public Component getComponent(String componentName) {
		for(Component c : this.components) {
			if(c.getName().equals(componentName))
				return c;
		}
		
		return null;
	}

	public String getProjectName() {
		return this.projectName;
	}

	/**
	 * Exports the project to the project xml file.
	 */
	public void export() {

	}
	
	public int numberOfComponents() {
		return this.components.size();
	}
	
	public int numberOfEntities() {
		return this.entities.size();
	}

	public static void main(String[] args) {
		String projectXMLFile = "testdata/.project";

		ProjectHandler handler = new ProjectHandler(projectXMLFile);
	}
}
